package ru.hh.school;


import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import static java.lang.System.*;

public class LoadTest {
    static final String SERVER_NAME = "localhost";
    static final int PORT = 12345;
    static final int ROUND_COUNT = 10;
    static final int THREAD_COUNT = 100;
    static final int ALLOWED_MAX = 100;
    static long roundTime;
    public static void main(String[] args) throws InterruptedException, ClassNotFoundException, IOException {
          int passed = 0;
          for (int round_num=0;round_num<ROUND_COUNT;++round_num) {
              CheckingThread[] threads = new CheckingThread[THREAD_COUNT];
              roundTime = currentTimeMillis() + 2000;
              for (int i=0;i<THREAD_COUNT;++i) {
                  threads[i] = (new CheckingThread(i, THREAD_COUNT));
              }
              for (int i=0;i<THREAD_COUNT;++i) {
                  threads[i].readjoins();
              }
              for (int i=0;i<THREAD_COUNT;++i) {
                  threads[i].start();
              }
              out.println("Starting round " + round_num + " in a second...");
              Thread.sleep(roundTime - currentTimeMillis());
              boolean hasAlive = true;
              int counter = 0;
              while (hasAlive) {
                  Thread.sleep(500);
                  out.println("waiting " + (counter++));
                  hasAlive = false;
                  for (int i=0;i<THREAD_COUNT;++i) {
                      hasAlive |= threads[i].isAlive();
//                      out.println("Thread "+i+" : "+threads[i].num+" "+threads[i].strs.size());
                  }
              }
              for (int i=0;i<THREAD_COUNT;++i) {
                  threads[i].close();
              }
              ArrayList<Long> zads = new ArrayList<Long>();
              System.out.println("Going to count...");
              for (int i=0;i<THREAD_COUNT;++i) {
                  for (int j=0;j<THREAD_COUNT;++j) {
                      for (int t=0;t<THREAD_COUNT;++t) {
                         if (threads[i].strs.get(j).contains("testingthread"+t+">")) {
                            long zad = (threads[i].times.get(j)-threads[t].actualSend);
                            zads.add(zad);
                         }
                      }
                  }
              }
              double avg = 0;
              for (long tt: zads) {
                  avg +=tt;
              }
              avg/=zads.size();
              long max = 0;
              for (long tt: zads) {
                  max = (max>tt)? max:tt;
              }
              double d = 0;
              for (long tt:zads) {
                  d=d+(avg-tt)*(avg-tt);
              }
              d/=zads.size();
              out.println("Finished round " + round_num+": avg = "+avg+" max = "+max+" d = "+Math.sqrt(d));
              if (max < ALLOWED_MAX) passed++;
          }
        System.out.println("Passed "+passed+" out of "+ROUND_COUNT);
    }
}

class CheckingThread extends Thread{
    Socket s;
    ObjectInputStream sin;
    ObjectOutputStream sout;
    int num, overall;
    long actualSend;
    public List<Long> times = new ArrayList<Long>();
    public List<String> strs = new ArrayList<String>();

    CheckingThread(int num, int overall) throws IOException, ClassNotFoundException {
        this.num = num;
        this.overall = overall;
        initSocket();
    }
    public void initSocket() throws IOException, ClassNotFoundException {
        s = new Socket(LoadTest.SERVER_NAME,LoadTest.PORT);
        sout = new ObjectOutputStream(s.getOutputStream());
        sin = new ObjectInputStream(s.getInputStream());
        sout.writeObject("/nick testingthread"+num);
        sin.readObject();
    }
    public void readjoins() throws ClassNotFoundException, IOException {
        for (int i=num+1;i<overall;++i) {
            sin.readObject();
        }
    }
    public void close() throws IOException {
        s.close();
    }
    public void run() {
        try {
            Thread.sleep(LoadTest.roundTime - currentTimeMillis());
            sout.writeObject("/send hui");
            actualSend = currentTimeMillis();
            for (int i=0;i<overall; ++i) {
                strs.add((String)sin.readObject());
                times.add(currentTimeMillis());
//                out.println("thread "+num+" : "+strs.get(strs.size()-1));

            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
